using System;
using System.DirectoryServices;
using CommandLineParser.Arguments;
using uTILLIty.ADExtractor.Core;

namespace uTILLIty.ADExtractor
{
	internal abstract class ExportCommandBase
	{
		[ValueArgument(typeof(string), 'q', "query", Optional = false,
			Description = "the LDAP query to perform", Example = "\"(&(objectCategory=User)(initials=*))\"",
			FullDescription = "The LDAP query must be in double-quotes, if it contains an ampersand or other commandline-reserved symbols!")]
		public string Query;

		[ValueArgument(typeof(string), 'f', "fields", Optional = false, DefaultValue = null,
			Description = "comma-separated list of properties", Example = "-f sn,sAMAccountName,count(member),all(member),RunID=Literal(1234)",
			FullDescription = @"The following aggregators are supported:
all:     exports all attribute-entries, separated using the mvsep argument
count:   returns the numer of entries found in the specified attribute/field
literal: returns the exact value specified")]
		public string PropertiesToLoad;

		[ValueArgument(typeof(string), 'm', "mvsep", Optional = true, DefaultValue = "|",
			Description = "the separator to use with the All() aggregate", Example = "-m ,")]
		public string MultiValueSeparator;

		[ValueArgument(typeof(string), 'c', "conn", Optional = true,
			Description = "an LDAP Connection-string", Example = "-c LDAP://mydomain.com")]
		public string LdapConnectionString;

		[ValueArgument(typeof(string), 'u', "user", Optional = true,
			Description = "a valid user-name on the target server/domain", Example = "-u admin")]
		public string LdapUsername;

		[ValueArgument(typeof(int), 'l', "limit", Optional = true, DefaultValue = 0,
			Description = "0 = use LDAP default (1000), all else returns all records found", Example = "-l 1",
			FullDescription = "see http://msdn.microsoft.com/en-us/library/system.directoryservices.directorysearcher.sizelimit.aspx.")]
		public int SizeLimit = 0;

		[ValueArgument(typeof(string), 'p', "pwd", Optional = true,
			Description = "the password corresponding to the supplied LDAP username", Example = "-p myPassword")]
		public string LdapPassword;

		[SwitchArgument('t', false, LongName = "quiet", Optional = true,
			Description = "Whether to show warnings and other non-data information", Example = "--quiet")]
		public bool Silent;

		protected virtual bool OnBeforeRunQuery(QueryInformation query)
		{
			return true;
		}

		protected abstract bool Export(QueryInformation query, SearchResultCollection result);

		public virtual string GetAdditionalHelpText()
		{
			return "";
		}

		public int Execute()
		{
			if (!EnsurePasswordIfUserSpecified())
				return 1;

			var query = BuildQueryInformation();
			if (!OnBeforeRunQuery(query))
				return 1;

			var result = RunQuery(query);

			return Export(query, result) ? 0 : 1;
		}

		protected virtual SearchResultCollection RunQuery(QueryInformation query)
		{
			var extractor = new ActiveDirectoryExtractor();
			SearchResultCollection result = extractor.QueryActiveDirectory(query);
			return result;
		}

		protected virtual QueryInformation BuildQueryInformation()
		{
			var query = new QueryInformation
			{
				Query = Query,
				PropertiesToLoad = AdPropertyInfo.Parse(PropertiesToLoad.Split(',')),
				LdapConnectionString = LdapConnectionString,
				Username = LdapUsername,
				Password = LdapPassword,
				SizeLimit = SizeLimit
			};
			return query;
		}

		protected virtual bool EnsurePasswordIfUserSpecified()
		{
			if (string.IsNullOrWhiteSpace(LdapUsername) || !String.IsNullOrWhiteSpace(LdapPassword))
				return true;

			AskForPassword();
			return !string.IsNullOrWhiteSpace(LdapPassword);
		}

		protected virtual void AskForPassword()
		{
			Console.WriteLine(Properties.Resources.EnterPassword);
			while (true)
			{
				var x = Console.ReadKey(true);
				if (x.Key == ConsoleKey.Enter)
				{
					break;
				}
				if (x.Key == ConsoleKey.Backspace)
				{
					if (LdapPassword.Length > 0)
					{
						LdapPassword = LdapPassword.Remove(LdapPassword.Length - 1);
						Console.Write(x.KeyChar);
						Console.Write(' ');
						Console.Write(x.KeyChar);
					}
				}
				else
				{
					LdapPassword += x.KeyChar;
					Console.Write('*');
				}
			}
			Console.WriteLine();
		}
	}
}